package  
{
	import org.flixel.*;
	
	/**
	 * ...
	 * @author Jay Wagner
	 */
	public class LevelTransition extends FlxGroup
	{
		public static const POINTS_PER_BULB_1:uint = 100;
		public static const POINTS_PER_BULB_2:uint = 175;
		public static const POINTS_PER_BULB_3:uint = 225;
		public static const POINTS_PER_SEC:uint = 25;
		public static const POINTS_ACCURACY_A:uint = 1500;
		public static const POINTS_ACCURACY_B:uint = 1000;
		public static const POINTS_ACCURACY_C:uint = 500;
		public static const POINTS_ACCURACY_F:uint = 0;
		public static const ACCURACY_LEVEL_B:uint = 84;
		public static const ACCURACY_LEVEL_C:uint = 74;
		public static const ACCURACY_LEVEL_F:uint = 50;
		
		public static const currentNumberOfLevels:uint = 5;
		
		private var _state:PlayState;
		
		private var _background:FlxSprite;
		private var _retryButton:FlxButton;
		private var _levelSelectButton:FlxButton;
		//private var _surveyButton:FlxButton;
		private var _nextLevelButton:FlxButton;
		private var _coinEarned:FlxSprite;
		
		public var completeBanner:FlxText;
		
		private var _finalY:Number;
		private var _pointsPerBulb:Array;
		private var _bulbScore:uint = 0;
		private var _timeLeft:uint = 0;
		private var _timeScore:uint = 0;
		private var _totalScore:uint = 0;
		private var _timeCounted:Boolean = false;
		private var _accuracyCounted:Boolean = false;
		private var _totalScoreCounted:Boolean = false;
		private var _exploded:Boolean = false;
		
		private var _timeFiredText:FlxText;
		private var _timeHitText:FlxText;
		private var _bulbScoreText:FlxText;
		private var _timeLeftText:FlxText;
		private var _timeScoreText:FlxText;
		private var _accuracyScoreText:FlxText;
		private var _accuracyText:FlxText;
		private var _totalScoreText:FlxText;
		private var _totalRatingText:FlxText;
		private var _levelEndReasonText:FlxText;
		
		private var _explodoUL:FlxEmitter;
		private var _explodoUR:FlxEmitter;
		private var _explodoLL:FlxEmitter;
		private var _explodoLR:FlxEmitter;
		
		private var _timeDelay:Number = 0;
		private var _accuracyDelay:Number = 0;
		private var _totalDelay:Number = 0;
		
		private var _lightbulbPowerLevels:FlxGroup;
		private var _lightbulbDelay:Number = 0;
		private var _lightbulbIndex:uint = 0;
		
		private const BUTTON_WIDTH:int = 100;
		private const BUTTON_HEIGHT:int = 26;
		private const FRAME_WIDTH:uint = 400;
		private const FRAME_HEIGHT:uint = 310;
		private const PIXELS_PER_EXPLODO:uint = 20;
		private const GRAVITY:uint = 300;
		
		public var ableToAdvance:Boolean = true;
		
		/**
		 * Constructor.
		 */
		public function LevelTransition()
		{
			_state = FlxG.state as PlayState;
			
			_pointsPerBulb = new Array(0, POINTS_PER_BULB_1, POINTS_PER_BULB_2, POINTS_PER_BULB_3);
			
			super();
			scrollFactor.x = 0;
			scrollFactor.y = 0;
			
			x = (FlxG.width - FRAME_WIDTH) / 2;
			y = -FRAME_HEIGHT;
			
			velocity.y = 450;
			
			_finalY = (FlxG.height - FRAME_HEIGHT) / 2;
			
			_background = new FlxSprite();
			add(_background.createGraphic(FRAME_WIDTH, FRAME_HEIGHT, 0xbb000000, true), true);
			
			_retryButton = new FlxButton(FRAME_WIDTH / 4 - BUTTON_WIDTH,  FRAME_HEIGHT - BUTTON_HEIGHT - 3, onRetry);
			_retryButton.scrollFactor.x = _retryButton.scrollFactor.y = 0;
			_retryButton.loadGraphic(new FlxSprite().loadGraphic(ImageFiles.button), new FlxSprite().loadGraphic(ImageFiles.buttonHighlight));
			var retryText:FlxText = new FlxText(0, 0, BUTTON_WIDTH, "Retry").setFormat("PowellAntique", 15, 0xDDDDDD, "center", 0xFF000000);
			var retryHighlight:FlxText = new FlxText(retryText.x, retryText.y, retryText.width, retryText.text).setFormat("PowellAntique", 15, 0xFFFFFF, "center", 0xFF000000);
			_retryButton.loadText(retryText, retryHighlight);
			add(_retryButton, true);
			
			_levelSelectButton = new FlxButton(FRAME_WIDTH / 2 - BUTTON_WIDTH / 2, FRAME_HEIGHT - BUTTON_HEIGHT - 3, onLevelSelect);
			_levelSelectButton.scrollFactor.x = _levelSelectButton.scrollFactor.y = 0;
			_levelSelectButton.loadGraphic(new FlxSprite().loadGraphic(ImageFiles.button), new FlxSprite().loadGraphic(ImageFiles.buttonHighlight));
			var levelSelectText:FlxText = new FlxText(0, 0, BUTTON_WIDTH, "Level Select").setFormat("PowellAntique", 15, 0xDDDDDD, "center", 0xFF000000);
			var levelSelectHighlight:FlxText = new FlxText(levelSelectText.x, levelSelectText.y, levelSelectText.width, levelSelectText.text).setFormat("PowellAntique", 15, 0xFFFFFF, "center", 0xFF000000);
			_levelSelectButton.loadText(levelSelectText, levelSelectHighlight);
			add(_levelSelectButton, true);
			
			_nextLevelButton = new FlxButton(3 * FRAME_WIDTH / 4, FRAME_HEIGHT - BUTTON_HEIGHT - 3, onNextLevel);
			_nextLevelButton.scrollFactor.x = _nextLevelButton.scrollFactor.y = 0;
			_nextLevelButton.loadGraphic(new FlxSprite().loadGraphic(ImageFiles.button), new FlxSprite().loadGraphic(ImageFiles.buttonHighlight));
			var nextLevelText:FlxText = new FlxText(0, 0, BUTTON_WIDTH, "Onward!").setFormat("PowellAntique", 15, 0xDDDDDD, "center", 0xFF000000);
			var nextLevelHighlight:FlxText = new FlxText(nextLevelText.x, nextLevelText.y, nextLevelText.width, nextLevelText.text).setFormat("PowellAntique", 15, 0xFFFFFF, "center", 0xFF000000);
			_nextLevelButton.loadText(nextLevelText, nextLevelHighlight);
			add(_nextLevelButton, true);
			
			(add(new FlxText(0, 0, FRAME_WIDTH, "level").setFormat("PowellAntique", 16, 0xffffff, "left"), true) as FlxText).alignment = "center";
			completeBanner = new FlxText(0, 18, FRAME_WIDTH, "COMPLETE").setFormat("PowellAntique", 20, 0xffffff, "center");
			if (!ableToAdvance)
			{
				completeBanner.text = "INCOMPLETE";
			}
			add(completeBanner, true);
			
			_levelEndReasonText = new FlxText(0, 50, FRAME_WIDTH).setFormat("PowellAntique", 14, 0xffffff, "center");
			_levelEndReasonText.scrollFactor.x = _levelEndReasonText.scrollFactor.y = 0;
			add(_levelEndReasonText);
			
			_timeFiredText = new FlxText(0, 30, FRAME_WIDTH);
			add(_timeFiredText, true);
			
			_timeHitText = new FlxText(0, 40, FRAME_WIDTH);
			add(_timeHitText, true);
			
			add(new FlxText(0, 180, FRAME_WIDTH, "BULBS").setFormat("PowellAntique", 18, 0xffffff, "left"), true);
			_bulbScoreText = new FlxText(0, 180, FRAME_WIDTH, "0").setFormat("PowellAntique", 18, 0xffffff, "right");
			add(_bulbScoreText, true);
			
			add(new FlxText(0, 200, FRAME_WIDTH, "TIME").setFormat("PowellAntique", 18, 0xffffff, "left"), true);
			_timeLeftText = new FlxText(200, 200, FRAME_WIDTH, "").setFormat("PowellAntique", 18, 0xffffff, "left");
			_timeScoreText = new FlxText(0, 200, FRAME_WIDTH, "0").setFormat("PowellAntique", 18, 0xffffff, "right");
			add(_timeLeftText, true);
			add(_timeScoreText, true);
			
			add(new FlxText(0, 220, FRAME_WIDTH, "ACCURACY").setFormat("PowellAntique", 18, 0xffffff, "left"), true);
			_accuracyText = new FlxText(200, 220, FRAME_WIDTH, "").setFormat("PowellAntique", 18, 0xffffff, "left");
			_accuracyScoreText = new FlxText(0, 220, FRAME_WIDTH, "0").setFormat("PowellAntique", 18, 0xffffff, "right");
			add(_accuracyText, true);
			add(_accuracyScoreText, true);
			
			add(new FlxText(0, 250, FRAME_WIDTH, "TOTAL").setFormat("PowellAntique", 18, 0xffffff, "left"), true);
			_totalRatingText = new FlxText(200, 250, FRAME_WIDTH).setFormat("PowellAntique", 18, 0xffffff, "left");
			_totalScoreText = new FlxText(0, 250, FRAME_WIDTH, "0").setFormat("PowellAntique", 18, 0xffffff, "right");
			add(_totalScoreText, true);
			add(_totalRatingText, true);
			
			_explodoUL = new FlxEmitter(FlxG.width / 4, FlxG.height / 4);
			_explodoUL.scrollFactor.x = _explodoUL.scrollFactor.y = 0;
			_explodoUL.gravity = GRAVITY;
			for (var i:int = 0; i < PIXELS_PER_EXPLODO; i++) 
			{
				var s:FlxSprite = new FlxSprite();
				s.createGraphic(2, 2, generateRandomPastel());
				_explodoUL.add(s, true);
			}
			
			_explodoUR = new FlxEmitter(3 * FlxG.width / 4, FlxG.height / 4);
			_explodoUR.scrollFactor.x = _explodoUR.scrollFactor.y = 0;
			_explodoUR.gravity = GRAVITY;
			for (i = 0; i < PIXELS_PER_EXPLODO; i++) 
			{
				s = new FlxSprite();
				s.createGraphic(2, 2, generateRandomPastel());
				_explodoUR.add(s, true);
			}
			
			_explodoLL = new FlxEmitter(FlxG.width / 4, 3 * FlxG.height / 4);
			_explodoLL.scrollFactor.x = _explodoLL.scrollFactor.y = 0;
			_explodoLL.gravity = GRAVITY;
			for (i = 0; i < PIXELS_PER_EXPLODO; i++) 
			{
				s = new FlxSprite();
				s.createGraphic(2, 2, generateRandomPastel());
				_explodoLL.add(s, true);
			}
			
			_explodoLR = new FlxEmitter(3 * FlxG.width / 4, 3 * FlxG.height / 4);
			_explodoLR.scrollFactor.x = _explodoLR.scrollFactor.y = 0;
			_explodoLR.gravity = GRAVITY;
			for (i = 0; i < PIXELS_PER_EXPLODO; i++) 
			{
				s = new FlxSprite();
				s.createGraphic(2, 2, generateRandomPastel());
				_explodoLR.add(s, true);
			}
			
			_coinEarned = new FlxSprite(FlxG.width / 2 - 100, FlxG.height);
			_coinEarned.scrollFactor.x = _coinEarned.scrollFactor.y = 0;
			_coinEarned.exists = false;
		}
		
		public function init():void
		{	
			// This function exists because we cannot know how many lightbulbs are on the level until we
			// load them with LoadOgmoObjects or whatever that function is called.
			_lightbulbPowerLevels = new FlxGroup();
			_lightbulbPowerLevels.scrollFactor.x = _lightbulbPowerLevels.scrollFactor.y = 0;
			var xOffset:uint = 0;
			var yOffset:uint = 80;
			
			for (var i:uint = 0; i < _state.lightBulbs.members.length; i++)
			{
				xOffset = i % 13 * 30;
				yOffset = 80 + uint(i / 13) * 32;
				var bulb:FlxSprite = new FlxSprite(xOffset, yOffset).createGraphic(30, 30, 0x00000000);				
				_lightbulbPowerLevels.add(bulb, true);
			}
			add(_lightbulbPowerLevels, true);
			add(_explodoUL);
			add(_explodoUR);
			add(_explodoLL);
			add(_explodoLR);
			add(_coinEarned, true);
		}
		
		public function InitiateTransition():void
		{
			exists = true;
			_totalScore = calculateTotalScore();
			FlxG.scores[FlxG.level] = Math.max(FlxG.scores[FlxG.level], _totalScore);
			
			FlxG.music.fadeOut(3.0);
		}
		
		override public function update():void
		{
			super.update();
			
			if (PlayState.calculateRating(_totalScore, FlxG.level) == PlayState.UNFINISHED)
			{
				ableToAdvance = false;
			}
			if (!ableToAdvance)
			{
				//change or remove next level button
				_nextLevelButton.exists = false;
				FlxG.scores[FlxG.level] = 0;
			}
			
			if (EndingState.isNextEndingUnlocked())
			{
				_levelSelectButton.exists = false;
				_retryButton.exists = false;
			}
			
			if (y >= _finalY)
			{
				switch(PlayState.whyLevelEnded)
				{
					case PlayState.TIMEUP:
					_levelEndReasonText.text = "- Time Up -";
					break;
					case PlayState.ALLLIGHTSLIT:
					_levelEndReasonText.text = "- All Lights Lit -";
					break;
					case PlayState.ALLPOWERGONE:
					_levelEndReasonText.text = "- All Power Gone -";
					break;
				}
				
				// We are in the final position, we can start displaying scores and such
				velocity.y = 0;
				
				// Display lightbulb count first
				if (_lightbulbIndex < _lightbulbPowerLevels.members.length)
				{
					if (_lightbulbDelay > .5)
					{
						var bulbSprite:FlxSprite = _lightbulbPowerLevels.members[_lightbulbIndex] as FlxSprite;
						var bulb:LightBulb = _state.lightBulbs.members[_lightbulbIndex] as LightBulb;
						var bulbPowerLevel:int = bulb.currentPowerLevel;
						_bulbScore += _pointsPerBulb[bulbPowerLevel];
						
						//plays different sound for each light bulb level
						switch (bulbPowerLevel)
						{
							case 0:
							bulbSprite.loadGraphic(ImageFiles.level0Bulb);
							FlxG.play(SoundFiles.level0BulbSound);
							break;
							case 1:
							bulbSprite.loadGraphic(ImageFiles.level1Bulb);
							FlxG.play(SoundFiles.level1BulbSound);
							break;
							case 2:
							bulbSprite.loadGraphic(ImageFiles.level2Bulb);
							FlxG.play(SoundFiles.level2BulbSound);
							break;
							case 3:
							bulbSprite.loadGraphic(ImageFiles.level3Bulb);
							FlxG.play(SoundFiles.level3BulbSound);
							break;
						}
						
						_bulbScoreText.text = _bulbScore.toString();
						_lightbulbIndex++;
						_lightbulbDelay = 0;
					}
					_lightbulbDelay += FlxG.elapsed;
				}
				else if (!_timeCounted) // All lightbulb scores have been counted, count time 
				{
					var tempTimeLeft:uint;
					var tempMin:uint;
					var tempSec:uint;
					
					tempTimeLeft = _timeLeft;
					
					while (tempTimeLeft > 60)
					{
						tempTimeLeft -= 60;
						tempMin ++;
					}
					tempSec = tempTimeLeft;
					
					//_timeLeftText.text = _timeLeft.toString();
					_timeLeftText.text = tempMin.toString() + ":";
					if (tempSec < 10)
					{
						_timeLeftText.text += '0';
					}
					_timeLeftText.text += tempSec;
					
					if (_timeDelay > .5)
					{
						if (_timeLeft > 0)
						{
							_timeLeft--;
							_timeScore += POINTS_PER_SEC;
							if (_timeLeft % 5 == 0)
							{
								FlxG.play(SoundFiles.blip);
							}
							_timeScoreText.text = _timeScore.toString();
						}
						else
						{
							_timeLeftText.text = "";
							_timeCounted = true;
						}
					}
					
					_timeDelay += FlxG.elapsed;
				}
				else if (!_accuracyCounted) // Time score has been counted, count accuracy
				{
					var accuracy:int = int(_state.lightning.timeHit / _state.lightning.timeFired * 100);
					
					if (accuracy <= ACCURACY_LEVEL_F)
					{
						_accuracyText.text = "F";
					}
					else if ((accuracy > ACCURACY_LEVEL_F) && (accuracy < ACCURACY_LEVEL_C))
					{
						_accuracyText.text = "C";
					}
					else if ((accuracy >= ACCURACY_LEVEL_C) && (accuracy < ACCURACY_LEVEL_B))
					{
						_accuracyText.text = "B";
					}
					else if (accuracy >= ACCURACY_LEVEL_B)
					{
						_accuracyText.text = "A";
					}
					
					if (_accuracyDelay > .5)
					{
						switch (_accuracyText.text)
						{
							case "A":
							FlxG.play(SoundFiles.level3BulbSound);
							_accuracyScoreText.text = POINTS_ACCURACY_A.toString();
							break;
							case "B":
							FlxG.play(SoundFiles.level2BulbSound);
							_accuracyScoreText.text = POINTS_ACCURACY_B.toString();
							break;
							case "C":
							FlxG.play(SoundFiles.level1BulbSound);
							_accuracyScoreText.text = POINTS_ACCURACY_C.toString();
							break;
							default:
							FlxG.play(SoundFiles.level0BulbSound);
							_accuracyScoreText.text = POINTS_ACCURACY_F.toString();
							break;							
						}
						
						_accuracyCounted = true;
					}
					
					_accuracyDelay += FlxG.elapsed;
				}
				else if (!_totalScoreCounted) // All scores have been calculated, figure out the total score
				{
					if (_totalDelay > .75)
					{
						_totalScoreText.text = _totalScore.toString();
						if (!ableToAdvance)
						{
							_totalScoreText.text = "0";
						}
					
						switch (PlayState.calculateRating(_totalScore, FlxG.level))
						{
							case PlayState.UNFINISHED:
							FlxG.play(SoundFiles.level0BulbSound);
							_totalRatingText.text = 'Unfinished';
							_coinEarned.createGraphic(1, 1, 0x00000000);
							break;
							case PlayState.BRONZE:
							FlxG.play(SoundFiles.level1BulbSound);
							_totalRatingText.text = 'Bronze';
							_coinEarned.loadGraphic(ImageFiles.coinBronzeBig);
							break;
							case PlayState.SILVER:
							FlxG.play(SoundFiles.level2BulbSound);
							_totalRatingText.text = 'Silver';
							_coinEarned.loadGraphic(ImageFiles.coinSilverBig);
							break;
							case PlayState.GOLD:
							FlxG.play(SoundFiles.level3BulbSound);
							_totalRatingText.text = 'Gold';
							_coinEarned.loadGraphic(ImageFiles.coinGoldBig);
							break;
						}
						
						if (!ableToAdvance)
						{
							_totalRatingText.text = 'Unfinished';
							_coinEarned.createGraphic(1, 1, 0x00000000);
						}
						
						_totalScoreCounted = true;
					}
					
					_totalDelay += FlxG.elapsed;
				}
				else // Scroll in the medal that the player earned
				{
					_coinEarned.velocity.y = -450;
					_coinEarned.exists = true;
					
					if (_coinEarned.y <= FlxG.height / 2 - 80)
					{
						_coinEarned.velocity.y = 0;
						
						// Play explosion
						if (!_exploded && ableToAdvance) 
						{
							switch (_totalRatingText.text) 
							{
								case 'Gold':
									_explodoUL.start();
									_explodoUR.start();
									_explodoLL.start();
									_explodoLR.start();
									FlxG.play(SoundFiles.goldEnding);
								break;
								case 'Silver':
									_explodoUL.y = FlxG.height / 2;
									_explodoUR.y = FlxG.height / 2;
									_explodoUL.start(true);
									_explodoUR.start(true);
									FlxG.play(SoundFiles.silverEnding);
								break;
								case 'Bronze':
									_explodoUL.x = FlxG.width / 2;
									_explodoUL.start(true);
									FlxG.play(SoundFiles.bronzeEnding);
								break;
								default:
									FlxG.play(SoundFiles.unfinishedEnding);
								break;
							}
							_exploded = true;
						}
					}
				}
			}
		}
		
		private function calculateTotalScore():uint
		{
			return calculateLightbulbScore() + calculateTimeScore() + calculateAccuracyScore();
		}
		
		private function calculateLightbulbScore():uint
		{
			var bulbScore:uint = 0;
			
			for (var i:int = 0; i < _lightbulbPowerLevels.members.length; i++)
			{
				var bulb:LightBulb = _state.lightBulbs.members[i] as LightBulb;
				var cpl:int = bulb.currentPowerLevel;
				bulbScore += _pointsPerBulb[cpl];
			}
			
			return bulbScore;
		}
		
		private function calculateTimeScore():uint
		{
			_timeLeft = _state.timerDisplay.time;
			return _timeLeft * POINTS_PER_SEC;
		}
		
		private function calculateAccuracyScore():uint
		{
			var accuracy:int = int(_state.lightning.timeHit / _state.lightning.timeFired * 100);
			
			if ((accuracy > ACCURACY_LEVEL_F) && (accuracy < ACCURACY_LEVEL_C))
			{
				return POINTS_ACCURACY_C;
			}
			else if ((accuracy >= ACCURACY_LEVEL_C) && (accuracy < ACCURACY_LEVEL_B))
			{
				return POINTS_ACCURACY_B;
			}
			else if (accuracy >= ACCURACY_LEVEL_B)
			{
				return POINTS_ACCURACY_A;
			}
			
			return POINTS_ACCURACY_F;
		}
		
		private function generateRandomPastel():uint
		{
			var red:uint = uint(Math.random() * 129) + 127;
			var green:uint = uint(Math.random() * 129) + 127;
			var blue:uint = uint(Math.random() * 129) + 127;
			
			return 255 << 24 | red << 16 | green << 8 | blue;
		}
		
		public static function onRetry():void
		{
			if (!FlxG.pause)
			{
				FlxG.play(SoundFiles.selectSound, 0.75);
				
				var state:PlayState = FlxG.state as PlayState;
				
				switch (FlxG.level)
				{
					case 0:
					FlxG.fade.start(0xFF000000, 1, toLevel0);
					break;
					case 1:
					FlxG.fade.start(0xFF000000, 1, toLevel1);
					break;
					case 2:
					FlxG.fade.start(0xFF000000, 1, toLevel2);
					break;
					case 3:
					FlxG.fade.start(0xFF000000, 1, toLevel3);
					break;
					case 4:
					FlxG.fade.start(0xFF000000, 1, toLevel4);
					break;
				}
			}
		}
		
		public function onLevelSelect():void
		{
			if (!FlxG.pause)
			{
				FlxG.play(SoundFiles.selectSound, 0.75);
				FlxG.fade.start(0xFF000000, 1, toLevelSelect);
			}
		}
		
		private function toLevelSelect():void
		{
			FlxG.state = new LevelSelectState();
		}
		
		public function onNextLevel():void
		{
			if (!FlxG.pause)
			{
				if (!PlayState.calculateRating(_totalScore, FlxG.level) == PlayState.UNFINISHED) //Doesn't advance level if level was unfinished
				{
					FlxG.play(SoundFiles.selectSound, 0.75);
					
					if (EndingState.isNextEndingUnlocked())
					{
						FlxG.fade.start(0xFF000000, 1, onFade);
					}
					else
					{
						switch (FlxG.level)
						{
							case 0:
							FlxG.fade.start(0xFF000000, 1, toLevel1);
							break;
							case 1:
							FlxG.fade.start(0xFF000000, 1, toLevel2);
							break;
							case 2:
							FlxG.fade.start(0xFF000000, 1, toLevel3);
							break;
							case 3:
							FlxG.fade.start(0xFF000000, 1, toLevel4);
							break;
							case 4:
							FlxG.fade.start(0xFF000000, 1, toLevelSelect);
						}
					}
				}
			}
		}
		
		public static function toLevel0():void
		{
			FlxG.level = 0;
			FlxG.state = new Level0State();
		}
		
		public static function toLevel1():void
		{
			FlxG.level = 1;
			FlxG.state = new Level1State();
		}
		
		public static function toLevel2():void
		{
			FlxG.level = 2;
			FlxG.state = new Level2State();
		}
		
		public static function toLevel3():void
		{
			FlxG.level = 3;
			FlxG.state = new Level3State();
		}
		
		public static function toLevel4():void
		{
			FlxG.level = 4;
			FlxG.state = new Level4State();
		}
		
		public static function onFade():void
		{
			FlxG.state = new EndingState;
		}
	}

}